Floyd算法+Bellman-ford 算法+SPFA算法

Floyd算法

核心语句

for(int k=0;k<n;k++){
            for(int i=0;i<n;i++)
                for(int j=0;j<n;j++){
                    if(cost[i][j]>cost[i][k]+cost[k][j])
                        cost[i][j]=cost[i][k]+cost[k][j];
                }
        }
}

完整代码

//floyd
//复杂度O(N^2)
#include<iostream>
#include<cstdio>
 
using namespace std;
 
const int INF=0x3f3f3f3f;
const int MAXN=1e3+50;
 
int mapp[MAXN][MAXN];
int N,M;
 
int main()
{
	scanf("%d%d",&N,&M);
	for(int i=1;i<=N;i++){
		for(int j=1;j<=M;j++){
			if(i==j){
				mapp[i][j]=0;
			}else{
				mapp[i][j]=INF;
			}
		}
	}
	int u,v,w;
	for(int i=1;i<=M;i++){
		scanf("%d%d%d",&u,&v,&w);
		mapp[u][v]=w;
	}
	for(int k=1;k<=N;k++){
		for(int i=1;i<=N;i++){
			for(int j=1;j<=N;j++){
				if(mapp[i][j]>mapp[i][k]+mapp[k][j]){
					mapp[i][j]=mapp[i][k]+mapp[k][j];
				}
			}
		}
	}
	for(int i=1;i<=N;i++){
		for(int j=1;j<=N;j++){
			printf("%10d",mapp[i][j]);
		}
		printf("\n");
	}
	return 0;
}

Bellman-Ford 算法

https://blog.csdn.net/liangzhaoyang1/article/details/51344742 

Bellman-ford算法是求含负权图的单源最短路径算法,效率很低,但代码很容易写。即进行持续地松弛(原文是这么写的,为什么要叫松弛,争议很大),每次松弛把每条边都更新一下,若n-1次松弛后还能更新,则说明图中有负环,无法得出结果,否则就成功完成。Bellman-ford算法有一个小优化:每次松弛先设一个标识flag,初值为FALSE,若有边更新则赋值为TRUE,最终如果还是FALSE则直接成功退出。

 for(int k=1;k<=n-1;k++)  //遍历点的次数
     {
            check=0;//用check检查是否进行下一轮次的操作
            for(int i=1;i<=m;i++)   //遍历边的次数
            {
                if(dis[v[i]]>dis[u[i]]+w[i]) //如果从u到v的距离能够通过w这条边压缩路径 就要进行松弛操作
                {
                    dis[v[i]]=dis[u[i]]+w[i];
                    check=1;
                }
            }
            if(check==0)break;
      }

Bellman-Ford算法浪费了许多时间做没有必要的松弛,

SPFA算法

在 Bellman-ford 算法的基础上加上一个队列优化,减少了冗余的松弛操作,是一种高效的最短路算法。

变量:

int s,t; //s为起点,t为终点

bool visit[ ]

int dis[t]  //从s到t的最短路径

int cnt[ ]  //如果某个点进入队列的次数大于等于 n,则存在负权回路,其中 n 为图的顶点数。

 

【初始化】

dist数组全部初始化为inf,visit数组为未访问

dist[s]=0

【松弛操作】

读取队头顶点u,将u出队,标记已访问,将与u相连的顶点v进行松弛操作,更新值,并且,如果v不在队列中,入队,标记已访问,如果在队列中就不用再入队,这样不断从队列中取出顶点来进行松弛操作。

以此循环,直到队空为止就完成了单源最短路的求解。

【负边】:如果某个点进入队列的次数大于等于 n,则存在负权回路,其中 n 为图的顶点数。

【模板】

//spafa
//复杂度O(KE)
#include<iostream>
#include<cstdio>
#include<queue>
#include<queue>
#include<cstring>
 
using namespace std;
 
const int MAXN=1010;
const int INF=0x3f3f3f3f;
 
struct edge{
    int v,cost;
    edge(int _v,int _cost):v(_v),cost(_cost){}
};
vector<edge>E[MAXN];
 
void add_edge(int u,int v,int w)
{
    E[u].push_back(edge(v,w));
}
 
bool vis[MAXN];
int cnt[MAXN];
int dist[MAXN];
 
bool spfa(int start,int n)
{
    memset(vis,false,sizeof(vis));
    for(int i=1;i<=n;i++){
        dist[i]=INF;
    }
    vis[start]=true;
    dist[start]=0;
    queue<int>que;
    while(!que.empty()){
        que.pop();
    }
    que.push(start);
    memset(cnt,0,sizeof(cnt));
    cnt[start]=1;
    while(!que.empty()){
        int u=que.front();
        que.pop();
        vis[u]=false;
        for(int i=0;i<E[u].size();i++){
            int v=E[u][i].v;
            if(dist[v]>dist[u]+E[u][i].cost){
                dist[v]=dist[u]+E[u][i].cost;
                if(!vis[v]){
                    vis[v]=true;
                    que.push(v);
                    if(++cnt[v]>n){
                        return false;
                    }
                }
            }
        }
    }
    return true;
}
 
int main()
{
 
    return 0;
}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值